#include <iostream>
#include <new>
#include <utility>

template <typename SIGNATURE, size_t STORAGE_SIZE = 128>
class Functional;

template <typename RET, typename... ARGS, size_t STORAGE_SIZE>
class Functional<RET(ARGS...), STORAGE_SIZE>
{
public:
    Functional() : m_function_ptr(nullptr), m_method_ptr(nullptr), m_alloc_ptr(nullptr) {}

    template <typename F>
    Functional(F &&f) : Functional()
    {
        static_assert(sizeof(F) <= STORAGE_SIZE,
                      "functional object doesn't fit into internal storage");
        static_assert(std::is_move_constructible<F>::value,
                      "functional object should be move-constructible");

        typedef typename std::remove_reference<F>::type T;

        // new (m_storage) T(std::move(f));

        m_method_ptr = [](void *obj, ARGS... args) -> RET
        {
            return static_cast<T *>(obj)->operator()(std::forward<ARGS>(args)...);
        };

        m_alloc_ptr = [](void *storage, void* obj)
        {
            if(obj)
            {
                T* x_object = static_cast<T*>(obj);
                new (storage) T(std::move(*x_object));
            }
            else
            {
                static_cast<T *>(obj)->~T();
            }
        };

        m_alloc_ptr(&m_storage, &f);
    }

    // template <typename T, typename M>
    // Functional(T *obj, M method) : m_function_ptr(nullptr), m_deleter_ptr(nullptr)
    // {
    //     m_method_ptr = [obj, method](void *, ARGS... args) -> RET
    //     {
    //         return (obj->*method)(std::forward<ARGS>(args)...);
    //     };
    // }

    Functional(RET (*function_ptr)(ARGS...)) : Functional()
    {
        m_function_ptr = function_ptr;
        // m_method_ptr = [function_ptr](FunctionPtr funcptr, ARGS... args) -> RET
        // {
        //     return (function_ptr)(std::forward<ARGS>(args)...);
        // };
    }

    Functional(Functional&& o) : Functional()
    {
        moveFromOther(o);
    }

    Functional& operator=(Functional&& o)
    {
        moveFromOther(o);
        return *this;
    }

    // Functional(RET (*function_ptr)(ARGS...)): Functional()
    // {
    //     m_function_ptr = function_ptr;
    //     // m_method_ptr = [function_ptr](FunctionPtr funcptr, ARGS... args) -> RET
    //     // {
    //     //     return (function_ptr)(std::forward<ARGS>(args)...);
    //     // };
    // }



    RET operator()(ARGS... args)
    {
        if (m_alloc_ptr)
        {
            return m_method_ptr(&m_storage, std::forward<ARGS>(args)...);
        }
        else if (m_function_ptr)
        {
            return m_function_ptr(std::forward<ARGS>(args)...);
        }
        else
        {
            throw std::runtime_error("call of empty Function");
        }
    }



    ~Functional()
    {
        if(m_alloc_ptr)
        {
            // std::cout << "可调用对象" << std::endl;
            m_alloc_ptr(&m_storage, nullptr);
        }
        else
        {
            // std::cout << "函数指针" << std::endl;
        }
    }

private:
    void moveFromOther(Functional& other)
    {
        if(this == &other)
            return;

        if(m_alloc_ptr)
        {
            m_alloc_ptr(&m_storage, nullptr);
            m_alloc_ptr = nullptr;
        }
        else
        {
            m_function_ptr = nullptr;
        }

        m_method_ptr = other.m_method_ptr;
        other.m_method_ptr = nullptr;

        if(other.m_alloc_ptr)
        {
            m_alloc_ptr = other.m_alloc_ptr;
            m_alloc_ptr(&m_storage, &other.m_storage);
        }
        else
        {
            // std::cout << "移动前：" << m_function_ptr << " " << other.m_function_ptr << std::endl;
            std::swap(m_function_ptr, other.m_function_ptr);
            // m_function_ptr = other.m_function_ptr;
            // std::cout << "移动后：" << m_function_ptr << " " << other.m_function_ptr << std::endl;
        }
    }



    typedef RET (*FunctionPtr)(ARGS...);
    typedef RET (*MethodPtr)(void *, ARGS...);
    typedef void (*AllocPtr)(void *, void*);

    union
    {
        FunctionPtr m_function_ptr;
        typename std::aligned_storage<STORAGE_SIZE, sizeof(size_t)>::type m_storage;
    };
    MethodPtr m_method_ptr;

    AllocPtr m_alloc_ptr;
};

// #include <iostream>
// #include <new>
// #include <utility>

// template <typename SIGNATURE, size_t STORAGE_SIZE = 128>
// class Functional;

// template <typename RET, typename... ARGS, size_t STORAGE_SIZE>
// class Functional<RET(ARGS...), STORAGE_SIZE>
// {
// public:
//     Functional() : m_function_ptr(nullptr), m_deleter_ptr(nullptr) {}

//     template <typename F>
//     Functional(F &&f) : m_function_ptr(nullptr), m_deleter_ptr(nullptr)
//     {
//         static_assert(sizeof(F) <= STORAGE_SIZE,
//                       "functional object doesn't fit into internal storage");
//         static_assert(std::is_move_constructible<F>::value,
//                       "functional object should be move-constructible");

//         typedef typename std::remove_reference<F>::type T;

//         new (m_storage) T(std::move(f));

//         m_method_ptr = [](void *obj, ARGS... args) -> RET
//         {
//             return static_cast<T *>(obj)->operator()(std::forward<ARGS>(args)...);
//         };

//         m_deleter_ptr = [](void *obj)
//         {
//             static_cast<T *>(obj)->~T();
//         };
//     }

//     template <typename T, typename M>
//     Functional(T *obj, M method) : m_function_ptr(nullptr), m_deleter_ptr(nullptr)
//     {
//         m_method_ptr = [obj, method](void *, ARGS... args) -> RET
//         {
//             return (obj->*method)(std::forward<ARGS>(args)...);
//         };
//     }

//     Functional(RET (*function_ptr)(ARGS...)) : m_function_ptr(nullptr), m_deleter_ptr(nullptr)
//     {
//         m_function_ptr = function_ptr;
//         // m_method_ptr = [function_ptr](FunctionPtr funcptr, ARGS... args) -> RET
//         // {
//         //     return (function_ptr)(std::forward<ARGS>(args)...);
//         // };
//     }

//     RET operator()(ARGS... args)
//     {
//         if (m_deleter_ptr)
//         {
//             return m_method_ptr(m_storage, std::forward<ARGS>(args)...);
//         }
//         else if (m_function_ptr)
//         {
//             return m_function_ptr(std::forward<ARGS>(args)...);
//         }
//         else
//         {
//             throw std::runtime_error("call of empty FixedFunction");
//         }
//     }

//     ~Functional()
//     {
//         if(m_deleter_ptr)
//         {
//             // std::cout << "可调用对象" << std::endl;
//             m_deleter_ptr(m_storage);
//         }
//         else
//         {
//             // std::cout << "函数指针" << std::endl;
//         }
//     }

// private:
//     typedef RET (*FunctionPtr)(ARGS...);
//     typedef RET (*MethodPtr)(void *, ARGS...);
//     typedef void (*DeleterPtr)(void *);

//     union
//     {
//         FunctionPtr m_function_ptr;
//         char m_storage[STORAGE_SIZE];
//     };
//     MethodPtr m_method_ptr;

//     DeleterPtr m_deleter_ptr;
// };

// #include <type_traits>
// #include <cstring>
// #include <stdexcept>
// #include <utility>

// template <typename SIGNATURE, size_t STORAGE_SIZE = 128>
// class Functional;

// template <typename RET, typename... Args, size_t STORAGE_SIZE>
// class Functional<RET(Args...), STORAGE_SIZE>
// {
//     typedef RET (*Func_Ptr_Type)(Args...);

// public:
//     Functional() : _func_ptr(nullptr), _method_ptr(nullptr), _alloc_ptr(nullptr)
//     {
//     }

//     template <typename Fn>
//     Functional(Fn &&object) : Functional()
//     {
//         typedef typename std::remove_reference<Fn> unref_type;

//         static_assert(sizeof(unref_type) < STORAGE_SIZE,
//                       "functional object doesn't fit into internal storage");
//         static_assert(std::is_move_constructible<unref_type>::value,
//                       "Should be of movable type");

//         // new (storage)

//         _method_ptr = [](void* object_ptr, Args... args) -> RET
//         {
//             return static_cast<unref_type*>(object_ptr)->operator()(args...);
//         };

//         _alloc_ptr = [](void *storage_ptr, void *object_ptr)
//         {
//             if (object_ptr)
//             {
//                 unref_type* x_object = static_cast<unref_type*>(object_ptr);
//                 new(storage_ptr) unref_type(std::move(*x_object));
//             }
//             else
//             {
//                 static_cast<unref_type*>(storage_ptr)->~unref_type();
//             }
//         };

//         _alloc_ptr(&_storage, &object);
//     }

//     // template <typename RET, typename... PARAMS>
//     // Functional(RET (*func_ptr)(PARAMS...)) : Functional()
//     // {
//     //     _func_ptr = func_ptr;

//     //     m_method_ptr = [](void*, func_ptr_type f_ptr, ARGS... args) -> R
//     //     {
//     //         return static_cast<RET (*)(PARAMS...)>(f_ptr)(args...);
//     //     };
//     // }

//     // template <typename RET, tyoename T, typename... PARAMS>
//     // Functional(T* object, PARAMS... args) : Functional()
//     // {
//     //     func_ptr =
//     // }

// private:
//     union
//     {
//         Func_Ptr_Type _func_ptr;
//         typename std::aligned_storage<STORAGE_SIZE, sizeof(size_t)>::type _storage;
//     };
//     typedef RET (*Method_Type)(void *object_ptr, Args... args);
//     Method_Type _method_ptr;

//     typedef void (*Alloc_Type)(void *storage_ptr, void *object_ptr);
//     Alloc_Type _alloc_ptr;
// };